package com.fullertontech.framework.generator;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import javax.sql.DataSource;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.JDBCConnectionConfiguration;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import org.mybatis.generator.config.JavaModelGeneratorConfiguration;
import org.mybatis.generator.config.JavaTypeResolverConfiguration;
import org.mybatis.generator.config.ModelType;
import org.mybatis.generator.config.PluginConfiguration;
import org.mybatis.generator.config.SqlMapGeneratorConfiguration;
import org.mybatis.generator.config.TableConfiguration;
import org.mybatis.generator.internal.DefaultShellCallback;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.StringUtils;
import com.fullertontech.framework.global.GlobalUtils;

/**
 * 代码生成配置
 * @author caojipian
 *
 */
@Configuration
@Conditional(GeneratorConditional.class)
public class GeneratorConfig implements ApplicationListener<ContextRefreshedEvent>{
	@Autowired
	private DataSource datasource;
	@Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Value("${jdbc.driverClassName}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
	
	private static GeneratorMetadata generatorMetadata;
	
	private org.mybatis.generator.config.Configuration configuration;
	
	private static final String contextName="context";
	
	private Class<? extends GeneratorFilter>[] filterClassList;
	
	private String targetProject;
	
	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		//判断注解
		EnableGenerator enableGenerator=GlobalUtils.getAnnotation(EnableGenerator.class);
		if(Objects.isNull(enableGenerator)) {
			return;
		}
		filterClassList=enableGenerator.filter();
		targetProject=enableGenerator.targetProject();
		//初始化元数据
		generatorMetadata=new GeneratorMetadata();
		generatorMetadata.setPackageName(GlobalUtils.getMainClassPackageName());
		generatorMetadata.setMapperPackageName(generatorMetadata.getPackageName().concat(".dao"));
		generatorMetadata.setModelPackageName(generatorMetadata.getPackageName().concat(".model"));
		
		//初始化generator配置
		initConfig(generatorMetadata);
		
		//获取所有表数据
		List<String> list=new JdbcTemplate(datasource).queryForList("show tables",String.class);
		list.forEach(this::dataPackage);
		//没有表数据则返回
		if(getContext().getTableConfigurations()==null||getContext().getTableConfigurations().isEmpty()) {
			return;
		}
		//代码生成
		generator();
	}
	
	public void dataPackage(String value) {
		boolean isGenerator=true;
		for(int i=0;i<filterClassList.length;i++) {
			try {
				GeneratorFilter generatorFilter=filterClassList[i].newInstance();
				isGenerator=generatorFilter.generatorTable(value);
				if(!isGenerator) {
					return;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		TableConfiguration tableConfiguration=new TableConfiguration(getContext());
		tableConfiguration.setTableName(value);
		getContext().addTableConfiguration(tableConfiguration);
	}
	
	public void initConfig(GeneratorMetadata generatorMetadata) {
		if(configuration==null) {
			configuration = new org.mybatis.generator.config.Configuration();
			Context context=new Context(ModelType.FLAT);
			context.setId(contextName);
			context.setTargetRuntime("MyBatis3Simple");
			context.addProperty("javaFileEncoding","UTF-8");
			
			JDBCConnectionConfiguration jdbcConnectionConfiguration=new JDBCConnectionConfiguration();
			jdbcConnectionConfiguration.setDriverClass(driver);
			jdbcConnectionConfiguration.setConnectionURL(url);
			jdbcConnectionConfiguration.setUserId(username);
			jdbcConnectionConfiguration.setPassword(password);
			context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);
			
			JavaTypeResolverConfiguration javaTypeResolverConfiguration=new JavaTypeResolverConfiguration();
	        javaTypeResolverConfiguration.setConfigurationType(MyJavaTypeResolver.class.getCanonicalName());
	        context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);
			
			JavaModelGeneratorConfiguration javaModelGeneratorConfiguration=new JavaModelGeneratorConfiguration();
			if(!StringUtils.isEmpty(targetProject)) {
				targetProject="../".concat(targetProject).concat("/");
			}
			javaModelGeneratorConfiguration.setTargetProject(targetProject+"src/main/java");
			javaModelGeneratorConfiguration.setTargetPackage(generatorMetadata.getModelPackageName());
			context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);
			
			SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration=new SqlMapGeneratorConfiguration();
			sqlMapGeneratorConfiguration.setTargetProject(targetProject+"src/main/resources");
			sqlMapGeneratorConfiguration.setTargetPackage("mapper");
			context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);
	
			JavaClientGeneratorConfiguration javaClientGeneratorConfiguration=new JavaClientGeneratorConfiguration();
			javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");
			javaClientGeneratorConfiguration.setTargetProject(targetProject+"src/main/java");
			javaClientGeneratorConfiguration.setTargetPackage(generatorMetadata.getMapperPackageName());
			context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);
			
			PluginConfiguration pluginConfiguration=new PluginConfiguration();
			pluginConfiguration.setConfigurationType(MyGeneratorPluginAdapter.class.getName());
			pluginConfiguration.addProperty("mappers", "tk.mybatis.mapper.common.Mapper");
			context.addPluginConfiguration(pluginConfiguration);
			
			
			/* 输出上下文环境的内容 */
			String xml=context.toXmlElement().getFormattedContent(1);
			System.out.println(xml);
			configuration.addContext(context);
		}
	}
	
	public Context getContext() {
		return configuration.getContext(contextName);
	}
	
	public GeneratorConfig generator() {
		/* 生成代码 */
		DefaultShellCallback callback = new DefaultShellCallback(true);
		try {
			MyBatisGenerator myBatisGenerator = new MyBatisGenerator(configuration, callback, new ArrayList<String>());
			myBatisGenerator.generate(null);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return this;
	}
}
